use crate::error::Error; use crate::User; use database::sqlx::SqliteExecutor; use database::Error as DatabaseError; use database::Users as DatabaseUsers; use email_address::EmailAddress; use hash::{PaperKey, Password}; use id::UserID; use std::str::FromStr; impl From for User { fn from(db: DatabaseUsers) -> Self { Self { id: UserID(db.id), created_at: db.created_at, updated_at: db.updated_at, is_admin: db.is_admin, username: db.username, name: db.name, email: db.email, password: db.password, password_recover: db.password_recover, paper_key: db.paper_key, is_archived: db.is_archived, timezone: db.timezone, } } } impl User { pub async fn get_initial_admin(conn: impl SqliteExecutor<'_>) -> Result, Error> { Ok(DatabaseUsers::get_initial_admin(conn) .await? .map(Self::from)) } pub async fn insert( conn: impl SqliteExecutor<'_>, id: &UserID, is_admin: bool, username: &str, password: Option<&Password>, ) -> Result, Error> { Ok( DatabaseUsers::insert(conn, &id.0, is_admin, username, password.map(|p| p.hash())) .await?, ) } async fn get_by_id(conn: impl SqliteExecutor<'_>, id: &UserID) -> Result, Error> { Ok(DatabaseUsers::get_one_by_id(conn, &id.0) .await? .map(Self::from)) } async fn get_by_email( conn: impl SqliteExecutor<'_>, email: &EmailAddress, ) -> Result, Error> { Ok(DatabaseUsers::get_one_by_email(conn, email.as_str()) .await? .map(Self::from)) } async fn get_by_username( conn: impl SqliteExecutor<'_>, username: &str, ) -> Result, Error> { Ok(DatabaseUsers::get_one_by_username(conn, username) .await? .map(Self::from)) } /// Get by ID, Email, Username (in that order) pub async fn get_by_login( conn: impl SqliteExecutor<'_>, login: &str, ) -> Result, Error> { // Parse login as ID if let Ok(id) = UserID::from_str(login) { return Self::get_by_id(conn, &id).await; } // Parse login as email if let Ok(email) = EmailAddress::from_str(login) { return Self::get_by_email(conn, &email).await; } // Get user from username Self::get_by_username(conn, login).await } pub async fn get_one_from_authorization_code( conn: impl SqliteExecutor<'_>, code: &str, ) -> Result, Error> { Ok(DatabaseUsers::get_one_from_authorization_code(conn, code) .await? .map(Self::from)) } pub async fn get_one_from_refresh_token( conn: impl SqliteExecutor<'_>, token: &str, ) -> Result, Error> { Ok(DatabaseUsers::get_one_from_refresh_token(conn, token) .await? .map(Self::from)) } pub async fn get_all(conn: impl SqliteExecutor<'_>) -> Result, Error> { Ok(DatabaseUsers::get_all(conn) .await? .into_iter() .map(Self::from) .collect::>()) } pub async fn set_username( &self, conn: impl SqliteExecutor<'_>, username: &str, ) -> Result<(), Error> { DatabaseUsers::set_username(conn, self.id.as_ref(), username) .await .map_err(|e| match e { DatabaseError::UniqueConstraint(column) => { if &column == "username" { Error::UsernameNotAvailable(username.into()) } else { Error::ColumnNotAvailable(column) } } _ => e.into(), })?; Ok(()) } pub async fn set_name(&self, conn: impl SqliteExecutor<'_>, name: &str) -> Result<(), Error> { DatabaseUsers::set_name(conn, self.id.as_ref(), name).await?; Ok(()) } pub async fn set_email( &self, conn: impl SqliteExecutor<'_>, email: EmailAddress, ) -> Result<(), Error> { let email = email.as_str(); DatabaseUsers::set_email(conn, self.id.as_ref(), email) .await .map_err(|e| match e { DatabaseError::UniqueConstraint(column) => { if &column == "email" { Error::EmailNotAvailable(email.into()) } else { Error::ColumnNotAvailable(column) } } _ => e.into(), })?; Ok(()) } pub async fn set_paper_key( &self, conn: impl SqliteExecutor<'_>, paper_key: Option<&PaperKey>, ) -> Result<(), Error> { let paper_key = paper_key.map(|paper_key| paper_key.hash()); DatabaseUsers::set_paper_key(conn, self.id.as_ref(), paper_key).await?; Ok(()) } pub async fn set_password( &self, conn: impl SqliteExecutor<'_>, password: Option<&Password>, ) -> Result<(), Error> { let password = password.map(|password| password.hash()); DatabaseUsers::set_password(conn, self.id.as_ref(), password).await?; Ok(()) } pub async fn set_timezone( &self, conn: impl SqliteExecutor<'_>, timezone: &str, ) -> Result<(), Error> { DatabaseUsers::set_timezone(conn, self.id.as_ref(), timezone).await?; Ok(()) } }