diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index a14e34eb..0f7f98d5 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -16,7 +16,7 @@ concurrency: env: CARGO_TERM_COLOR: always - rust_min: 1.89.0 + rust_min: 1.90.0 jobs: rustfmt: diff --git a/src/assignment/backends/error.rs b/src/assignment/backends/error.rs index ed7ac09f..ac6150ef 100644 --- a/src/assignment/backends/error.rs +++ b/src/assignment/backends/error.rs @@ -40,30 +40,45 @@ pub enum AssignmentDatabaseError { source: RoleBuilderError, }, - #[error(transparent)] - Database { source: sea_orm::DbErr }, - /// Conflict - #[error("{0}")] - Conflict(String), + #[error("{message}")] + Conflict { message: String, context: String }, /// SqlError - #[error("{0}")] - Sql(String), + #[error("{message}")] + Sql { message: String, context: String }, + + /// Database error + #[error("Database error while {context}")] + Database { + source: sea_orm::DbErr, + context: String, + }, #[error("{0}")] InvalidAssignmentType(String), } -impl From for AssignmentDatabaseError { - fn from(err: sea_orm::DbErr) -> Self { - err.sql_err().map_or_else( - || Self::Database { source: err }, - |err| match err { - SqlErr::UniqueConstraintViolation(descr) => Self::Conflict(descr), - SqlErr::ForeignKeyConstraintViolation(descr) => Self::Conflict(descr), - other => Self::Sql(other.to_string()), +/// Convert the DB error into the [AssignmentDatabaseError] with the context information. +pub fn db_err(e: sea_orm::DbErr, context: &str) -> AssignmentDatabaseError { + e.sql_err().map_or_else( + || AssignmentDatabaseError::Database { + source: e, + context: context.to_string(), + }, + |err| match err { + SqlErr::UniqueConstraintViolation(descr) => AssignmentDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + SqlErr::ForeignKeyConstraintViolation(descr) => AssignmentDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + other => AssignmentDatabaseError::Sql { + message: other.to_string(), + context: context.to_string(), }, - ) - } + }, + ) } diff --git a/src/assignment/backends/sql/assignment.rs b/src/assignment/backends/sql/assignment.rs index 801f54fe..b972c462 100644 --- a/src/assignment/backends/sql/assignment.rs +++ b/src/assignment/backends/sql/assignment.rs @@ -18,7 +18,7 @@ use sea_orm::prelude::Expr; use sea_orm::query::*; use std::collections::{BTreeMap, HashMap}; -use crate::assignment::backends::error::AssignmentDatabaseError; +use crate::assignment::backends::error::{AssignmentDatabaseError, db_err}; use crate::assignment::types::*; use crate::config::Config; use crate::db::entity::{ @@ -71,15 +71,19 @@ pub async fn list( } let results: Result, _> = if let Some(true) = ¶ms.include_names { - let db_assignments: Vec<(db_assignment::Model, Option)> = - select_assignment.find_also_related(DbRole).all(db).await?; + let db_assignments: Vec<(db_assignment::Model, Option)> = select_assignment + .find_also_related(DbRole) + .all(db) + .await + .map_err(|err| db_err(err, "fetching role assignments with roles"))?; let db_system_assignments: Vec<(db_system_assignment::Model, Option)> = if params.project_id.is_none() && params.domain_id.is_none() { // get system scope assignments only when no project or domain is specified select_system_assignment .find_also_related(DbRole) .all(db) - .await? + .await + .map_err(|err| db_err(err, "fetching system role assignments with roles"))? } else { Vec::new() }; @@ -93,11 +97,17 @@ pub async fn list( ) .collect() } else { - let db_assignments: Vec = select_assignment.all(db).await?; + let db_assignments: Vec = select_assignment + .all(db) + .await + .map_err(|err| db_err(err, "fetching role assignments"))?; let db_system_assignments: Vec = if params.project_id.is_none() && params.domain_id.is_none() { // get system scope assignments only when no project or domain is specified - select_system_assignment.all(db).await? + select_system_assignment + .all(db) + .await + .map_err(|err| db_err(err, "fetching system role assignments"))? } else { Vec::new() }; @@ -153,7 +163,12 @@ pub async fn list_for_multiple_actors_and_targets( let mut db_assignments: BTreeMap = BTreeMap::new(); // Get assignments resolving the roles inference - for assignment in select.all(db).await? { + for assignment in select.all(db).await.map_err(|err| { + db_err( + err, + "fetching role assignments for multiple actors and targets", + ) + })? { db_assignments.insert(assignment.role_id.clone(), assignment.clone()); if let Some(implies) = imply_rules.get(&assignment.role_id) { let mut implied_assignment = assignment.clone(); @@ -173,7 +188,8 @@ pub async fn list_for_multiple_actors_and_targets( .filter(Expr::col(db_role::Column::Id).is_in(db_assignments.keys())) .into_tuple() .all(db) - .await?, + .await + .map_err(|err| db_err(err, "fetching roles by ids"))?, ); let results: Result, _> = db_assignments .values() diff --git a/src/assignment/backends/sql/implied_role.rs b/src/assignment/backends/sql/implied_role.rs index 900bcefb..583ff7df 100644 --- a/src/assignment/backends/sql/implied_role.rs +++ b/src/assignment/backends/sql/implied_role.rs @@ -16,7 +16,7 @@ use sea_orm::DatabaseConnection; use sea_orm::entity::*; use std::collections::{BTreeMap, BTreeSet}; -use crate::assignment::backends::error::AssignmentDatabaseError; +use crate::assignment::backends::error::{AssignmentDatabaseError, db_err}; use crate::db::entity::prelude::ImpliedRole as DbImpliedRole; /// Build a resolved tree of role inference @@ -52,7 +52,11 @@ pub async fn list_rules( resolve: bool, ) -> Result>, AssignmentDatabaseError> { let mut implied_rules: BTreeMap> = BTreeMap::new(); - for imply in DbImpliedRole::find().all(db).await? { + for imply in DbImpliedRole::find() + .all(db) + .await + .map_err(|err| db_err(err, "fetching implied roles"))? + { implied_rules .entry(imply.prior_role_id) .and_modify(|x| { diff --git a/src/assignment/backends/sql/role.rs b/src/assignment/backends/sql/role.rs index 4a50f441..7185c6f1 100644 --- a/src/assignment/backends/sql/role.rs +++ b/src/assignment/backends/sql/role.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use sea_orm::query::*; use serde_json::Value; -use crate::assignment::backends::error::AssignmentDatabaseError; +use crate::assignment::backends::error::{AssignmentDatabaseError, db_err}; use crate::assignment::types::*; use crate::config::Config; use crate::db::entity::{prelude::Role as DbRole, role as db_role}; @@ -31,7 +31,10 @@ pub async fn get>( ) -> Result, AssignmentDatabaseError> { let role_select = DbRole::find_by_id(id.as_ref()); - let entry: Option = role_select.one(db).await?; + let entry: Option = role_select + .one(db) + .await + .map_err(|err| db_err(err, "fetching role by id"))?; entry.map(TryInto::try_into).transpose() } @@ -49,7 +52,10 @@ pub async fn list( select = select.filter(db_role::Column::Name.eq(name)); } - let db_roles: Vec = select.all(db).await?; + let db_roles: Vec = select + .all(db) + .await + .map_err(|err| db_err(err, "listing roles"))?; let results: Result, _> = db_roles .into_iter() .map(TryInto::::try_into) diff --git a/src/assignment/error.rs b/src/assignment/error.rs index a25db3ad..06b47969 100644 --- a/src/assignment/error.rs +++ b/src/assignment/error.rs @@ -72,7 +72,7 @@ pub enum AssignmentProviderError { impl From for AssignmentProviderError { fn from(source: AssignmentDatabaseError) -> Self { match source { - AssignmentDatabaseError::Conflict(x) => Self::Conflict(x), + AssignmentDatabaseError::Conflict { message, .. } => Self::Conflict(message), AssignmentDatabaseError::RoleNotFound(x) => Self::RoleNotFound(x), AssignmentDatabaseError::Serde { source } => Self::Serde { source }, _ => Self::AssignmentDatabaseError { source }, diff --git a/src/catalog/backends/error.rs b/src/catalog/backends/error.rs index b7a3de5d..e6f6967d 100644 --- a/src/catalog/backends/error.rs +++ b/src/catalog/backends/error.rs @@ -41,27 +41,41 @@ pub enum CatalogDatabaseError { ServiceNotFound(String), /// Conflict - #[error("{0}")] - Conflict(String), + #[error("{message}")] + Conflict { message: String, context: String }, /// SqlError - #[error("{0}")] - Sql(String), + #[error("{message}")] + Sql { message: String, context: String }, /// Database error - #[error(transparent)] - Database { source: sea_orm::DbErr }, + #[error("Database error while {context}")] + Database { + source: sea_orm::DbErr, + context: String, + }, } -impl From for CatalogDatabaseError { - fn from(err: sea_orm::DbErr) -> Self { - err.sql_err().map_or_else( - || Self::Database { source: err }, - |err| match err { - SqlErr::UniqueConstraintViolation(descr) => Self::Conflict(descr), - SqlErr::ForeignKeyConstraintViolation(descr) => Self::Conflict(descr), - other => Self::Sql(other.to_string()), +/// Convert the DB error into the [CatalogDatabaseError] with the context information. +pub fn db_err(e: sea_orm::DbErr, context: &str) -> CatalogDatabaseError { + e.sql_err().map_or_else( + || CatalogDatabaseError::Database { + source: e, + context: context.to_string(), + }, + |err| match err { + SqlErr::UniqueConstraintViolation(descr) => CatalogDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + SqlErr::ForeignKeyConstraintViolation(descr) => CatalogDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + other => CatalogDatabaseError::Sql { + message: other.to_string(), + context: context.to_string(), }, - ) - } + }, + ) } diff --git a/src/catalog/backends/sql.rs b/src/catalog/backends/sql.rs index a9dc60f0..1ea4dff6 100644 --- a/src/catalog/backends/sql.rs +++ b/src/catalog/backends/sql.rs @@ -19,7 +19,7 @@ use sea_orm::query::*; use super::super::types::*; use crate::catalog::CatalogProviderError; -use crate::catalog::backends::error::CatalogDatabaseError; +use crate::catalog::backends::error::{CatalogDatabaseError, db_err}; use crate::config::Config; use crate::db::entity::{ endpoint as db_endpoint, @@ -104,7 +104,8 @@ async fn get_catalog( .find_with_related(DbEndpoint) .filter(db_endpoint::Column::Enabled.eq(enabled)) .all(db) - .await?; + .await + .map_err(|err| db_err(err, "fetching catalog"))?; let mut res: Vec<(Service, Vec)> = Vec::new(); for (srv, db_endpoints) in db_entities.into_iter() { diff --git a/src/catalog/backends/sql/endpoint.rs b/src/catalog/backends/sql/endpoint.rs index 39a237b5..761a97a8 100644 --- a/src/catalog/backends/sql/endpoint.rs +++ b/src/catalog/backends/sql/endpoint.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use sea_orm::query::*; use serde_json::Value; -use crate::catalog::backends::error::CatalogDatabaseError; +use crate::catalog::backends::error::{CatalogDatabaseError, db_err}; use crate::catalog::types::*; use crate::config::Config; use crate::db::entity::{endpoint as db_endpoint, prelude::Endpoint as DbEndpoint}; @@ -29,7 +29,10 @@ pub async fn get>( ) -> Result, CatalogDatabaseError> { let select = DbEndpoint::find_by_id(id.as_ref()); - let entry: Option = select.one(db).await?; + let entry: Option = select + .one(db) + .await + .map_err(|err| db_err(err, "fetching service endpoint by id"))?; entry.map(TryInto::try_into).transpose() } @@ -50,7 +53,10 @@ pub async fn list( select = select.filter(db_endpoint::Column::RegionId.eq(val)); } - let db_entities: Vec = select.all(db).await?; + let db_entities: Vec = select + .all(db) + .await + .map_err(|err| db_err(err, "fetching endpoints"))?; let results: Result, _> = db_entities .into_iter() .map(TryInto::::try_into) diff --git a/src/catalog/backends/sql/service.rs b/src/catalog/backends/sql/service.rs index 061d9a01..07a6587a 100644 --- a/src/catalog/backends/sql/service.rs +++ b/src/catalog/backends/sql/service.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use sea_orm::query::*; use serde_json::Value; -use crate::catalog::backends::error::CatalogDatabaseError; +use crate::catalog::backends::error::{CatalogDatabaseError, db_err}; use crate::catalog::types::*; use crate::config::Config; use crate::db::entity::{prelude::Service as DbService, service as db_service}; @@ -29,7 +29,10 @@ pub async fn get>( ) -> Result, CatalogDatabaseError> { let select = DbService::find_by_id(id.as_ref()); - let entry: Option = select.one(db).await?; + let entry: Option = select + .one(db) + .await + .map_err(|err| db_err(err, "fetching service by ID"))?; entry.map(TryInto::try_into).transpose() } @@ -44,7 +47,10 @@ pub async fn list( select = select.filter(db_service::Column::Type.eq(typ)); } - let db_services: Vec = select.all(db).await?; + let db_services: Vec = select + .all(db) + .await + .map_err(|err| db_err(err, "fetching services"))?; let results: Result, _> = db_services .into_iter() .map(TryInto::::try_into) diff --git a/src/federation/backends/error.rs b/src/federation/backends/error.rs index 9ec2d241..70af2f99 100644 --- a/src/federation/backends/error.rs +++ b/src/federation/backends/error.rs @@ -25,8 +25,19 @@ pub enum FederationDatabaseError { source: serde_json::Error, }, - #[error(transparent)] - Database { source: sea_orm::DbErr }, + /// Conflict + #[error("{message}")] + Conflict { message: String, context: String }, + + /// SqlError + #[error("{message}")] + Sql { message: String, context: String }, + + #[error("Database error while {context}")] + Database { + source: sea_orm::DbErr, + context: String, + }, #[error("{0}")] IdentityProviderNotFound(String), @@ -37,14 +48,6 @@ pub enum FederationDatabaseError { #[error("{0}")] AuthStateNotFound(String), - /// Conflict - #[error("{0}")] - Conflict(String), - - /// SqlError - #[error("{0}")] - Sql(String), - #[error(transparent)] AuthStateBuilder { #[from] @@ -64,15 +67,26 @@ pub enum FederationDatabaseError { }, } -impl From for FederationDatabaseError { - fn from(err: sea_orm::DbErr) -> Self { - err.sql_err().map_or_else( - || Self::Database { source: err }, - |err| match err { - SqlErr::UniqueConstraintViolation(descr) => Self::Conflict(descr), - SqlErr::ForeignKeyConstraintViolation(descr) => Self::Conflict(descr), - other => Self::Sql(other.to_string()), +/// Convert the DB error into the [FederationDatabaseError] with the context information. +pub fn db_err(e: sea_orm::DbErr, context: &str) -> FederationDatabaseError { + e.sql_err().map_or_else( + || FederationDatabaseError::Database { + source: e, + context: context.to_string(), + }, + |err| match err { + SqlErr::UniqueConstraintViolation(descr) => FederationDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + SqlErr::ForeignKeyConstraintViolation(descr) => FederationDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + other => FederationDatabaseError::Sql { + message: other.to_string(), + context: context.to_string(), }, - ) - } + }, + ) } diff --git a/src/federation/backends/sql/auth_state/create.rs b/src/federation/backends/sql/auth_state/create.rs index d7fb8913..b7d2ee84 100644 --- a/src/federation/backends/sql/auth_state/create.rs +++ b/src/federation/backends/sql/auth_state/create.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use crate::config::Config; use crate::db::entity::federated_auth_state as db_federated_auth_state; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn create( @@ -41,7 +41,10 @@ pub async fn create( requested_scope: scope.map(Set).unwrap_or(NotSet).into(), }; - let db_entry: db_federated_auth_state::Model = entry.insert(db).await?; + let db_entry: db_federated_auth_state::Model = entry + .insert(db) + .await + .map_err(|err| db_err(err, "persisting federation login auth_state"))?; db_entry.try_into() } diff --git a/src/federation/backends/sql/auth_state/delete.rs b/src/federation/backends/sql/auth_state/delete.rs index 91afabff..82c107f4 100644 --- a/src/federation/backends/sql/auth_state/delete.rs +++ b/src/federation/backends/sql/auth_state/delete.rs @@ -22,7 +22,7 @@ use crate::db::entity::{ federated_auth_state as db_federated_auth_state, prelude::FederatedAuthState as DbFederatedAuthState, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; pub async fn delete>( _conf: &Config, @@ -31,7 +31,8 @@ pub async fn delete>( ) -> Result<(), FederationDatabaseError> { let res = DbFederatedAuthState::delete_by_id(id.as_ref()) .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "deleting federation login auth_state"))?; if res.rows_affected == 1 { Ok(()) } else { @@ -48,7 +49,8 @@ pub async fn delete_expired( DbFederatedAuthState::delete_many() .filter(db_federated_auth_state::Column::ExpiresAt.lt(Utc::now())) .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "deleting expired federation login auth_states"))?; Ok(()) } diff --git a/src/federation/backends/sql/auth_state/get.rs b/src/federation/backends/sql/auth_state/get.rs index 51aaaa96..c1901a42 100644 --- a/src/federation/backends/sql/auth_state/get.rs +++ b/src/federation/backends/sql/auth_state/get.rs @@ -20,7 +20,7 @@ use crate::db::entity::{ federated_auth_state as db_federated_auth_state, prelude::FederatedAuthState as DbFederatedAuthState, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn get>( @@ -30,7 +30,10 @@ pub async fn get>( ) -> Result, FederationDatabaseError> { let select = DbFederatedAuthState::find_by_id(state.as_ref()); - let entry: Option = select.one(db).await?; + let entry: Option = select + .one(db) + .await + .map_err(|err| db_err(err, "fetching federation login auth_state by id"))?; entry.map(TryInto::try_into).transpose() } diff --git a/src/federation/backends/sql/identity_provider/create.rs b/src/federation/backends/sql/identity_provider/create.rs index 093dd60c..2af0f30f 100644 --- a/src/federation/backends/sql/identity_provider/create.rs +++ b/src/federation/backends/sql/identity_provider/create.rs @@ -22,7 +22,7 @@ use crate::db::entity::{ federation_protocol as db_old_federation_protocol, identity_provider as db_old_identity_provider, mapping as db_old_mapping, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn create( @@ -80,7 +80,10 @@ pub async fn create( .unwrap_or(NotSet), }; - let db_entry: db_federated_identity_provider::Model = entry.insert(db).await?; + let db_entry: db_federated_identity_provider::Model = entry + .insert(db) + .await + .map_err(|err| db_err(err, "persisting new identity provider"))?; // For compatibility reasons add entry for the IDP old-style as well as the protocol to keep // constraints working @@ -92,7 +95,8 @@ pub async fn create( authorization_ttl: NotSet, } .insert(db) - .await?; + .await + .map_err(|err| db_err(err, "persisting v3 identity provider"))?; db_old_federation_protocol::ActiveModel { id: Set("oidc".into()), @@ -101,7 +105,8 @@ pub async fn create( remote_id_attribute: NotSet, } .insert(db) - .await?; + .await + .map_err(|err| db_err(err, "persisting v3 federation oidc protocol"))?; db_old_federation_protocol::ActiveModel { id: Set("jwt".into()), @@ -110,7 +115,8 @@ pub async fn create( remote_id_attribute: NotSet, } .insert(db) - .await?; + .await + .map_err(|err| db_err(err, "persisting v3 federation jwt protocol"))?; db_old_mapping::Entity::insert(db_old_mapping::ActiveModel { id: Set("dummy".into()), @@ -126,7 +132,8 @@ pub async fn create( ) .on_empty_do_nothing() .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "persisting v3 federation mapping"))?; db_entry.try_into() } diff --git a/src/federation/backends/sql/identity_provider/delete.rs b/src/federation/backends/sql/identity_provider/delete.rs index 16f9950a..8716d1a0 100644 --- a/src/federation/backends/sql/identity_provider/delete.rs +++ b/src/federation/backends/sql/identity_provider/delete.rs @@ -20,7 +20,7 @@ use crate::db::entity::prelude::{ FederatedIdentityProvider as DbFederatedIdentityProvider, IdentityProvider as DbIdentityProvider, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; pub async fn delete>( _conf: &Config, @@ -29,11 +29,13 @@ pub async fn delete>( ) -> Result<(), FederationDatabaseError> { let res = DbFederatedIdentityProvider::delete_by_id(id.as_ref()) .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "deleting identity provider"))?; if res.rows_affected == 1 { DbIdentityProvider::delete_by_id(id.as_ref()) .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "deleting v3 identity provider"))?; Ok(()) } else { Err(FederationDatabaseError::IdentityProviderNotFound( diff --git a/src/federation/backends/sql/identity_provider/get.rs b/src/federation/backends/sql/identity_provider/get.rs index 61dcf67c..1cf38e88 100644 --- a/src/federation/backends/sql/identity_provider/get.rs +++ b/src/federation/backends/sql/identity_provider/get.rs @@ -20,7 +20,7 @@ use crate::db::entity::{ federated_identity_provider as db_federated_identity_provider, prelude::FederatedIdentityProvider as DbFederatedIdentityProvider, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn get>( @@ -30,7 +30,10 @@ pub async fn get>( ) -> Result, FederationDatabaseError> { let select = DbFederatedIdentityProvider::find_by_id(id.as_ref()); - let entry: Option = select.one(db).await?; + let entry: Option = select + .one(db) + .await + .map_err(|err| db_err(err, "fetching identity provider by id"))?; entry.map(TryInto::try_into).transpose() } #[cfg(test)] diff --git a/src/federation/backends/sql/identity_provider/list.rs b/src/federation/backends/sql/identity_provider/list.rs index 7e5a11dd..d3e5635a 100644 --- a/src/federation/backends/sql/identity_provider/list.rs +++ b/src/federation/backends/sql/identity_provider/list.rs @@ -21,7 +21,7 @@ use crate::db::entity::{ federated_identity_provider as db_federated_identity_provider, prelude::FederatedIdentityProvider as DbFederatedIdentityProvider, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn list( @@ -48,7 +48,10 @@ pub async fn list( }; } - let db_entities: Vec = select.all(db).await?; + let db_entities: Vec = select + .all(db) + .await + .map_err(|err| db_err(err, "listing identity providers"))?; let results: Result, _> = db_entities .into_iter() .map(TryInto::::try_into) diff --git a/src/federation/backends/sql/identity_provider/update.rs b/src/federation/backends/sql/identity_provider/update.rs index ba2c81d9..c0f71e5c 100644 --- a/src/federation/backends/sql/identity_provider/update.rs +++ b/src/federation/backends/sql/identity_provider/update.rs @@ -20,7 +20,7 @@ use crate::db::entity::{ federated_identity_provider as db_federated_identity_provider, prelude::FederatedIdentityProvider as DbFederatedIdentityProvider, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn update>( @@ -31,7 +31,8 @@ pub async fn update>( ) -> Result { if let Some(current) = DbFederatedIdentityProvider::find_by_id(id.as_ref()) .one(db) - .await? + .await + .map_err(|err| db_err(err, "fetching current identity provider data for update"))? { let mut entry: db_federated_identity_provider::ActiveModel = current.into(); if let Some(val) = idp.name { @@ -68,7 +69,10 @@ pub async fn update>( entry.default_mapping_name = Set(val.to_owned()); } - let db_entry: db_federated_identity_provider::Model = entry.update(db).await?; + let db_entry: db_federated_identity_provider::Model = entry + .update(db) + .await + .map_err(|err| db_err(err, "updating identity provider"))?; db_entry.try_into() } else { Err(FederationDatabaseError::IdentityProviderNotFound( diff --git a/src/federation/backends/sql/mapping/create.rs b/src/federation/backends/sql/mapping/create.rs index 193774b0..f81b17fb 100644 --- a/src/federation/backends/sql/mapping/create.rs +++ b/src/federation/backends/sql/mapping/create.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use crate::config::Config; use crate::db::entity::federated_mapping as db_federated_mapping; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn create( @@ -88,7 +88,10 @@ pub async fn create( .into(), }; - let db_entry: db_federated_mapping::Model = entry.insert(db).await?; + let db_entry: db_federated_mapping::Model = entry + .insert(db) + .await + .map_err(|err| db_err(err, "persisting new federation mapping"))?; db_entry.try_into() } diff --git a/src/federation/backends/sql/mapping/delete.rs b/src/federation/backends/sql/mapping/delete.rs index 257529f5..8f6b5f9f 100644 --- a/src/federation/backends/sql/mapping/delete.rs +++ b/src/federation/backends/sql/mapping/delete.rs @@ -17,7 +17,7 @@ use sea_orm::entity::*; use crate::config::Config; use crate::db::entity::prelude::FederatedMapping as DbFederatedMapping; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; pub async fn delete>( _conf: &Config, @@ -26,7 +26,8 @@ pub async fn delete>( ) -> Result<(), FederationDatabaseError> { let res = DbFederatedMapping::delete_by_id(id.as_ref()) .exec(db) - .await?; + .await + .map_err(|err| db_err(err, "deleting federation mapping by id"))?; if res.rows_affected == 1 { Ok(()) } else { diff --git a/src/federation/backends/sql/mapping/get.rs b/src/federation/backends/sql/mapping/get.rs index 751b2642..d0146e34 100644 --- a/src/federation/backends/sql/mapping/get.rs +++ b/src/federation/backends/sql/mapping/get.rs @@ -19,7 +19,7 @@ use crate::config::Config; use crate::db::entity::{ federated_mapping as db_federated_mapping, prelude::FederatedMapping as DbFederatedMapping, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn get>( @@ -29,7 +29,10 @@ pub async fn get>( ) -> Result, FederationDatabaseError> { let select = DbFederatedMapping::find_by_id(id.as_ref()); - let entry: Option = select.one(db).await?; + let entry: Option = select + .one(db) + .await + .map_err(|err| db_err(err, "fetching federation mapping by id"))?; entry.map(TryInto::try_into).transpose() } diff --git a/src/federation/backends/sql/mapping/list.rs b/src/federation/backends/sql/mapping/list.rs index 3be507a7..e720302c 100644 --- a/src/federation/backends/sql/mapping/list.rs +++ b/src/federation/backends/sql/mapping/list.rs @@ -21,7 +21,7 @@ use crate::db::entity::{ federated_mapping as db_federated_mapping, prelude::FederatedMapping as DbFederatedMapping, sea_orm_active_enums::MappingType as db_mapping_type, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn list( @@ -47,7 +47,10 @@ pub async fn list( select = select.filter(db_federated_mapping::Column::r#Type.eq(db_mapping_type::from(val))); } - let db_entities: Vec = select.all(db).await?; + let db_entities: Vec = select + .all(db) + .await + .map_err(|err| db_err(err, "fetching mappings"))?; let results: Result, _> = db_entities .into_iter() .map(TryInto::::try_into) diff --git a/src/federation/backends/sql/mapping/update.rs b/src/federation/backends/sql/mapping/update.rs index 5dd44710..929f002b 100644 --- a/src/federation/backends/sql/mapping/update.rs +++ b/src/federation/backends/sql/mapping/update.rs @@ -19,7 +19,7 @@ use crate::config::Config; use crate::db::entity::{ federated_mapping as db_federated_mapping, prelude::FederatedMapping as DbFederatedMapping, }; -use crate::federation::backends::error::FederationDatabaseError; +use crate::federation::backends::error::{FederationDatabaseError, db_err}; use crate::federation::types::*; pub async fn update>( @@ -28,7 +28,11 @@ pub async fn update>( id: S, mapping: MappingUpdate, ) -> Result { - if let Some(current) = DbFederatedMapping::find_by_id(id.as_ref()).one(db).await? { + if let Some(current) = DbFederatedMapping::find_by_id(id.as_ref()) + .one(db) + .await + .map_err(|err| db_err(err, "fetching mapping by id for update"))? + { let mut entry: db_federated_mapping::ActiveModel = current.into(); if let Some(val) = mapping.name { entry.name = Set(val.to_owned()); @@ -73,7 +77,10 @@ pub async fn update>( entry.token_restriction_id = Set(Some(val.to_owned())); } - let db_entry: db_federated_mapping::Model = entry.update(db).await?; + let db_entry: db_federated_mapping::Model = entry + .update(db) + .await + .map_err(|err| db_err(err, "updating the mapping"))?; db_entry.try_into() } else { Err(FederationDatabaseError::MappingNotFound( diff --git a/src/federation/error.rs b/src/federation/error.rs index 903469a3..8e358637 100644 --- a/src/federation/error.rs +++ b/src/federation/error.rs @@ -61,7 +61,7 @@ impl From for FederationProviderError { Self::IdentityProviderNotFound(x) } FederationDatabaseError::MappingNotFound(x) => Self::MappingNotFound(x), - FederationDatabaseError::Conflict(x) => Self::Conflict(x), + FederationDatabaseError::Conflict { message, .. } => Self::Conflict(message), FederationDatabaseError::Serde { source } => Self::Serde { source }, _ => Self::FederationDatabase { source }, } diff --git a/src/identity/backends/error.rs b/src/identity/backends/error.rs index 0958bf90..1c1f6d42 100644 --- a/src/identity/backends/error.rs +++ b/src/identity/backends/error.rs @@ -77,7 +77,7 @@ pub enum IdentityDatabaseError { UserIdOrNameWithDomain, } -/// Convert the DB error into the IdentityDatabaseError with the context information. +/// Convert the DB error into the [IdentityDatabaseError] with the context information. pub fn db_err(e: sea_orm::DbErr, context: &str) -> IdentityDatabaseError { e.sql_err().map_or_else( || IdentityDatabaseError::Database { diff --git a/src/resource/backends/error.rs b/src/resource/backends/error.rs index e24fdd00..0d29eea1 100644 --- a/src/resource/backends/error.rs +++ b/src/resource/backends/error.rs @@ -41,26 +41,40 @@ pub enum ResourceDatabaseError { }, /// Conflict - #[error("{0}")] - Conflict(String), + #[error("{message}")] + Conflict { message: String, context: String }, /// SqlError - #[error("{0}")] - Sql(String), + #[error("{message}")] + Sql { message: String, context: String }, - #[error(transparent)] - Database { source: sea_orm::DbErr }, + #[error("Database error while {context}")] + Database { + source: sea_orm::DbErr, + context: String, + }, } -impl From for ResourceDatabaseError { - fn from(err: sea_orm::DbErr) -> Self { - err.sql_err().map_or_else( - || Self::Database { source: err }, - |err| match err { - SqlErr::UniqueConstraintViolation(descr) => Self::Conflict(descr), - SqlErr::ForeignKeyConstraintViolation(descr) => Self::Conflict(descr), - other => Self::Sql(other.to_string()), +/// Convert the DB error into the [ResourceDatabaseError] with the context information. +pub fn db_err(e: sea_orm::DbErr, context: &str) -> ResourceDatabaseError { + e.sql_err().map_or_else( + || ResourceDatabaseError::Database { + source: e, + context: context.to_string(), + }, + |err| match err { + SqlErr::UniqueConstraintViolation(descr) => ResourceDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + SqlErr::ForeignKeyConstraintViolation(descr) => ResourceDatabaseError::Conflict { + message: descr.to_string(), + context: context.to_string(), + }, + other => ResourceDatabaseError::Sql { + message: other.to_string(), + context: context.to_string(), }, - ) - } + }, + ) } diff --git a/src/resource/backends/sql.rs b/src/resource/backends/sql.rs index 97258c4c..7e73d58e 100644 --- a/src/resource/backends/sql.rs +++ b/src/resource/backends/sql.rs @@ -22,7 +22,7 @@ use super::super::types::*; use crate::config::Config; use crate::db::entity::{prelude::Project as DbProject, project as db_project}; use crate::resource::ResourceProviderError; -use crate::resource::backends::error::ResourceDatabaseError; +use crate::resource::backends::error::{ResourceDatabaseError, db_err}; #[derive(Clone, Debug, Default)] pub struct SqlBackend { @@ -84,7 +84,10 @@ pub async fn get_domain_by_id>( let domain_select = DbProject::find_by_id(domain_id.as_ref()).filter(db_project::Column::IsDomain.eq(true)); - let domain_entry: Option = domain_select.one(db).await?; + let domain_entry: Option = domain_select + .one(db) + .await + .map_err(|err| db_err(err, "fetching domain by id"))?; domain_entry.map(TryInto::try_into).transpose() } @@ -97,19 +100,25 @@ pub async fn get_domain_by_name>( .filter(db_project::Column::IsDomain.eq(true)) .filter(db_project::Column::Name.eq(domain_name.as_ref())); - let domain_entry: Option = domain_select.one(db).await?; + let domain_entry: Option = domain_select + .one(db) + .await + .map_err(|err| db_err(err, "fetching domain by name"))?; domain_entry.map(TryInto::try_into).transpose() } pub async fn get_project>( _conf: &Config, db: &DatabaseConnection, - domain_id: I, + id: I, ) -> Result, ResourceDatabaseError> { let project_select = - DbProject::find_by_id(domain_id.as_ref()).filter(db_project::Column::IsDomain.eq(false)); + DbProject::find_by_id(id.as_ref()).filter(db_project::Column::IsDomain.eq(false)); - let project_entry: Option = project_select.one(db).await?; + let project_entry: Option = project_select + .one(db) + .await + .map_err(|err| db_err(err, "fetching project by id"))?; project_entry.map(TryInto::try_into).transpose() } @@ -124,7 +133,10 @@ pub async fn get_project_by_name, D: AsRef>( .filter(db_project::Column::Name.eq(name.as_ref())) .filter(db_project::Column::DomainId.eq(domain_id.as_ref())); - let project_entry: Option = project_select.one(db).await?; + let project_entry: Option = project_select + .one(db) + .await + .map_err(|err| db_err(err, "fetching project by name and domain"))?; project_entry.map(TryInto::try_into).transpose() } diff --git a/src/resource/error.rs b/src/resource/error.rs index 5bed85ee..ee6458f5 100644 --- a/src/resource/error.rs +++ b/src/resource/error.rs @@ -51,7 +51,7 @@ pub enum ResourceProviderError { impl From for ResourceProviderError { fn from(source: ResourceDatabaseError) -> Self { match source { - ResourceDatabaseError::Conflict(x) => Self::Conflict(x), + ResourceDatabaseError::Conflict { message, .. } => Self::Conflict(message), ResourceDatabaseError::DomainNotFound(x) => Self::DomainNotFound(x), _ => Self::ResourceDatabase { source }, }