use crate::{crypto::Encryption, env::Env, init_admin::create_default_admin_if_none}; use wither::mongodb::{options::ClientOptions, Client, Database}; #[derive(Debug, Clone)] /// The app_state that must be given to the actix::App instance using App::new().app_data(web::Data::new(AppState::new())) /// It holds the database client connection, an Env struct which provides all values defined in the .env file, /// and an Encryption struct which is reponsible for encrypting and decrypting data such as passwords and auth tokens. pub struct AppState { pub db: Database, pub env: Env, pub encryption: Encryption, } impl AppState { /// Creates the Mongodb database client connection async fn get_db_connection(host: &str, env: &Env) -> Database { let db_connection_string = format!( "mongodb://{}:{}@{}:{}/{}", env.db_username, env.db_user_pwd, host, env.db_port, env.db_name ); let client_options = ClientOptions::parse(&db_connection_string) .await .expect("Error creating database client options"); let client = Client::with_options(client_options).expect("Couldn't connect to database."); client.database(&env.db_name) } pub async fn new() -> Self { let env = Env::new(); let db = Self::get_db_connection(&env.db_name, &env).await; let encryption = Encryption::new(env.crypt_key.to_owned()); AppState { db, env, encryption, } } /// This calls Self::new() and creates a default administrator before returning the instance pub async fn with_default_admin_user() -> Self { let instance = Self::new().await; if let Err(e) = create_default_admin_if_none(&instance).await { panic!("Error creating admin user: {}\nWill exit process now.", e); }; instance } #[cfg(test)] /// Provides an instance with some specificities for testing pub async fn for_test() -> Self { let env = Env::for_test(); let db = Self::get_db_connection("localhost", &env).await; let encryption = Encryption::new(env.crypt_key.to_owned()); AppState { db, env, encryption, } } }