use std::collections::{BTreeMap, BTreeSet}; use serde::{Deserialize, Serialize}; use thiserror::Error; use crate::core::{ database_privileges::{DatabasePrivilegeRow, DatabasePrivilegeRowDiff, DatabasePrivilegesDiff}, protocol::request_validation::ValidationError, types::{DbOrUser, MySQLDatabase, MySQLUser}, }; pub type ModifyPrivilegesRequest = BTreeSet; pub type ModifyPrivilegesResponse = BTreeMap<(MySQLDatabase, MySQLUser), Result<(), ModifyDatabasePrivilegesError>>; #[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum ModifyDatabasePrivilegesError { #[error("Database validation error: {0}")] DatabaseValidationError(ValidationError), #[error("User validation error: {0}")] UserValidationError(ValidationError), #[error("Database does not exist")] DatabaseDoesNotExist, #[error("User does not exist")] UserDoesNotExist, #[error("Diff does not apply: {0}")] DiffDoesNotApply(DiffDoesNotApplyError), #[error("MySQL error: {0}")] MySqlError(String), } #[allow(clippy::enum_variant_names)] #[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum DiffDoesNotApplyError { #[error("Privileges row already exists for database '{0}' and user '{1}'")] RowAlreadyExists(MySQLDatabase, MySQLUser), #[error("Privileges row does not exist for database '{0}' and user '{1}'")] RowDoesNotExist(MySQLDatabase, MySQLUser), #[error("Privilege change '{0:?}' does not apply to row '{1:?}'")] RowPrivilegeChangeDoesNotApply(DatabasePrivilegeRowDiff, DatabasePrivilegeRow), } pub fn print_modify_database_privileges_output_status(output: &ModifyPrivilegesResponse) { for ((database_name, username), result) in output { match result { Ok(()) => { println!( "Privileges for user '{}' on database '{}' modified successfully.", username, database_name ); } Err(err) => { eprintln!("{}", err.to_error_message(database_name, username)); eprintln!("Skipping..."); } } println!(); } } impl ModifyDatabasePrivilegesError { pub fn to_error_message(&self, database_name: &MySQLDatabase, username: &MySQLUser) -> String { match self { ModifyDatabasePrivilegesError::DatabaseValidationError(err) => { err.to_error_message(DbOrUser::Database(database_name.clone())) } ModifyDatabasePrivilegesError::UserValidationError(err) => { err.to_error_message(DbOrUser::User(username.clone())) } ModifyDatabasePrivilegesError::DatabaseDoesNotExist => { format!("Database '{}' does not exist.", database_name) } ModifyDatabasePrivilegesError::UserDoesNotExist => { format!("User '{}' does not exist.", username) } ModifyDatabasePrivilegesError::DiffDoesNotApply(diff) => { format!( "Could not apply privilege change:\n{}", diff.to_error_message() ) } ModifyDatabasePrivilegesError::MySqlError(err) => { format!("MySQL error: {}", err) } } } #[allow(dead_code)] pub fn error_type(&self) -> String { match self { // TODO: should these be subtyped? ModifyDatabasePrivilegesError::DatabaseValidationError(err) => err.error_type(), ModifyDatabasePrivilegesError::UserValidationError(err) => err.error_type(), ModifyDatabasePrivilegesError::DatabaseDoesNotExist => { "database-does-not-exist".to_string() } ModifyDatabasePrivilegesError::UserDoesNotExist => "user-does-not-exist".to_string(), ModifyDatabasePrivilegesError::DiffDoesNotApply(err) => { format!("diff-does-not-apply/{}", err.error_type()) } ModifyDatabasePrivilegesError::MySqlError(_) => "mysql-error".to_string(), } } } impl DiffDoesNotApplyError { pub fn to_error_message(&self) -> String { match self { DiffDoesNotApplyError::RowAlreadyExists(database_name, username) => { format!( "Privileges for user '{}' on database '{}' already exist.", username, database_name ) } DiffDoesNotApplyError::RowDoesNotExist(database_name, username) => { format!( "Privileges for user '{}' on database '{}' do not exist.", username, database_name ) } DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(diff, row) => { format!( "Could not apply privilege change {:?} to row {:?}", diff, row ) } } } pub fn error_type(&self) -> String { match self { DiffDoesNotApplyError::RowAlreadyExists(_, _) => "row-already-exists".to_string(), DiffDoesNotApplyError::RowDoesNotExist(_, _) => "row-does-not-exist".to_string(), DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(_, _) => { "row-privilege-change-does-not-apply".to_string() } } } }