diff --git a/src/domain/mod.rs b/src/domain/mod.rs index 062ae9d..d3f7dbb 100644 --- a/src/domain/mod.rs +++ b/src/domain/mod.rs @@ -1 +1,2 @@ pub mod handler; +pub mod sql_tables; diff --git a/src/domain/sql_tables.rs b/src/domain/sql_tables.rs new file mode 100644 index 0000000..f21c102 --- /dev/null +++ b/src/domain/sql_tables.rs @@ -0,0 +1,82 @@ +use sqlx::any::AnyPool; + +pub async fn init_table(pool: &AnyPool) -> sqlx::Result<()> { + // SQLite needs this pragma to be turned on. Other DB might not understand this, so ignore the + // error. + let _ = sqlx::query("PRAGMA foreign_keys = ON").execute(pool).await; + sqlx::query( + "CREATE TABLE IF NOT EXISTS users ( + user_id NVARCHAR(255) PRIMARY KEY, + email NVARCHAR(255) NOT NULL, + display_name NVARCHAR(255) NOT NULL, + first_name NVARCHAR(255) NOT NULL, + last_name NVARCHAR(255) NOT NULL, + avatar Blob, + creation_date DateTime NOT NULL, + password NVARCHAR(255) NOT NULL, + totp_secret VARCHAR(64), + mfa_type Text + )", + ) + .execute(pool) + .await?; + sqlx::query( + "CREATE TABLE IF NOT EXISTS groups ( + group_id integer PRIMARY KEY AUTOINCREMENT, + display_name NVARCHAR(255) NOT NULL + )", + ) + .execute(pool) + .await?; + sqlx::query( + "CREATE TABLE IF NOT EXISTS membership ( + user_id NVARCHAR(255) PRIMARY KEY, + group_id integer NOT NULL, + FOREIGN KEY (user_id) + REFERENCES users (user_id), + FOREIGN KEY (group_id) + REFERENCES groups (group_id) + )", + ) + .execute(pool) + .await?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use sqlx::{Column, Row}; + + #[derive(sqlx::FromRow)] + struct UserName(String); + + #[actix_rt::test] + async fn test_init_table() { + let sql_pool = sqlx::any::AnyPoolOptions::new() + .connect("sqlite::memory:") + .await + .unwrap(); + init_table(&sql_pool).await.unwrap(); + sqlx::query(r#"INSERT INTO users + (user_id, email, display_name, first_name, last_name, creation_date, password) + VALUES ("bôb", "böb@bob.bob", "Bob Bobbersön", "Bob", "Bobberson", CURRENT_TIMESTAMP, "bob00")"#).execute(&sql_pool).await.unwrap(); + let row = sqlx::query(r#"SELECT display_name FROM users WHERE user_id = "bôb""#) + .fetch_one(&sql_pool) + .await + .unwrap(); + assert_eq!(row.column(0).name(), "display_name"); + assert_eq!(row.get::("display_name"), "Bob Bobbersön"); + } + + #[actix_rt::test] + async fn test_already_init_table() { + let sql_pool = sqlx::any::AnyPoolOptions::new() + .connect("sqlite::memory:") + .await + .unwrap(); + init_table(&sql_pool).await.unwrap(); + init_table(&sql_pool).await.unwrap(); + } +} diff --git a/src/main.rs b/src/main.rs index 9cf0a8e..64f26a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,7 @@ async fn run_server(config: Configuration) -> Result<()> { .max_connections(5) .connect(&config.database_url) .await?; + domain::sql_tables::init_table(&sql_pool).await?; let backend_handler = domain::handler::SqlBackendHandler::new(config.clone(), sql_pool.clone()); let server_builder = infra::ldap_server::build_ldap_server( &config,