Wrap database users and database names in newtypes

Also, use less cloning where possible
This commit was merged in pull request #81.
This commit is contained in:
2024-08-20 17:46:43 +02:00
parent 8c2754c9d7
commit a0be0d3b92
15 changed files with 355 additions and 260 deletions

View File

@@ -54,7 +54,7 @@ impl UnixUser {
Ok(UnixUser {
username: libc_user.name,
groups: groups.iter().map(|g| g.name.clone()).collect(),
groups: groups.iter().map(|g| g.name.to_owned()).collect(),
})
}

View File

@@ -7,7 +7,10 @@ use std::{
collections::{BTreeSet, HashMap},
};
use super::common::{rev_yn, yn};
use super::{
common::{rev_yn, yn},
protocol::{MySQLDatabase, MySQLUser},
};
use crate::server::sql::database_privilege_operations::{
DatabasePrivilegeRow, DATABASE_PRIVILEGE_FIELDS,
};
@@ -35,8 +38,8 @@ pub fn diff(row1: &DatabasePrivilegeRow, row2: &DatabasePrivilegeRow) -> Databas
debug_assert!(row1.db == row2.db && row1.user == row2.user);
DatabasePrivilegeRowDiff {
db: row1.db.clone(),
user: row1.user.clone(),
db: row1.db.to_owned(),
user: row1.user.to_owned(),
diff: DATABASE_PRIVILEGE_FIELDS
.into_iter()
.skip(2)
@@ -70,8 +73,8 @@ pub fn parse_privilege_table_cli_arg(arg: &str) -> anyhow::Result<DatabasePrivil
anyhow::bail!("Username cannot be empty.");
}
let db = parts[0].to_string();
let user = parts[1].to_string();
let db = parts[0].into();
let user = parts[1].into();
let privs = parts[2].to_string();
let mut result = DatabasePrivilegeRow {
@@ -165,11 +168,11 @@ const EDITOR_COMMENT: &str = r#"
pub fn generate_editor_content_from_privilege_data(
privilege_data: &[DatabasePrivilegeRow],
unix_user: &str,
database_name: Option<&str>,
database_name: Option<&MySQLDatabase>,
) -> String {
let example_user = format!("{}_user", unix_user);
let example_db = database_name
.unwrap_or(&format!("{}_db", unix_user))
.unwrap_or(&format!("{}_db", unix_user).into())
.to_string();
// NOTE: `.max()`` fails when the iterator is empty.
@@ -206,8 +209,8 @@ pub fn generate_editor_content_from_privilege_data(
let example_line = format_privileges_line_for_editor(
&DatabasePrivilegeRow {
db: example_db,
user: example_user,
db: example_db.into(),
user: example_user.into(),
select_priv: true,
insert_priv: true,
update_priv: true,
@@ -298,8 +301,8 @@ fn parse_privilege_row_from_editor(row: &str) -> PrivilegeRowParseResult {
}
let row = DatabasePrivilegeRow {
db: (*parts.first().unwrap()).to_owned(),
user: (*parts.get(1).unwrap()).to_owned(),
db: (*parts.first().unwrap()).into(),
user: (*parts.get(1).unwrap()).into(),
select_priv: match parse_privilege_cell_from_editor(
parts.get(2).unwrap(),
DATABASE_PRIVILEGE_FIELDS[2],
@@ -423,8 +426,8 @@ pub fn parse_privilege_data_from_editor_content(
/// The `User` and `Database` are the same for both instances.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
pub struct DatabasePrivilegeRowDiff {
pub db: String,
pub user: String,
pub db: MySQLDatabase,
pub user: MySQLUser,
pub diff: BTreeSet<DatabasePrivilegeChange>,
}
@@ -454,7 +457,7 @@ pub enum DatabasePrivilegesDiff {
}
impl DatabasePrivilegesDiff {
pub fn get_database_name(&self) -> &str {
pub fn get_database_name(&self) -> &MySQLDatabase {
match self {
DatabasePrivilegesDiff::New(p) => &p.db,
DatabasePrivilegesDiff::Modified(p) => &p.db,
@@ -462,7 +465,7 @@ impl DatabasePrivilegesDiff {
}
}
pub fn get_user_name(&self) -> &str {
pub fn get_user_name(&self) -> &MySQLUser {
match self {
DatabasePrivilegesDiff::New(p) => &p.user,
DatabasePrivilegesDiff::Modified(p) => &p.user,
@@ -478,34 +481,36 @@ pub fn diff_privileges(
from: &[DatabasePrivilegeRow],
to: &[DatabasePrivilegeRow],
) -> BTreeSet<DatabasePrivilegesDiff> {
let from_lookup_table: HashMap<(String, String), DatabasePrivilegeRow> = HashMap::from_iter(
from.iter()
.cloned()
.map(|p| ((p.db.clone(), p.user.clone()), p)),
);
let from_lookup_table: HashMap<(MySQLDatabase, MySQLUser), DatabasePrivilegeRow> =
HashMap::from_iter(
from.iter()
.cloned()
.map(|p| ((p.db.to_owned(), p.user.to_owned()), p)),
);
let to_lookup_table: HashMap<(String, String), DatabasePrivilegeRow> = HashMap::from_iter(
to.iter()
.cloned()
.map(|p| ((p.db.clone(), p.user.clone()), p)),
);
let to_lookup_table: HashMap<(MySQLDatabase, MySQLUser), DatabasePrivilegeRow> =
HashMap::from_iter(
to.iter()
.cloned()
.map(|p| ((p.db.to_owned(), p.user.to_owned()), p)),
);
let mut result = BTreeSet::new();
for p in to {
if let Some(old_p) = from_lookup_table.get(&(p.db.clone(), p.user.clone())) {
if let Some(old_p) = from_lookup_table.get(&(p.db.to_owned(), p.user.to_owned())) {
let diff = diff(old_p, p);
if !diff.diff.is_empty() {
result.insert(DatabasePrivilegesDiff::Modified(diff));
}
} else {
result.insert(DatabasePrivilegesDiff::New(p.clone()));
result.insert(DatabasePrivilegesDiff::New(p.to_owned()));
}
}
for p in from {
if !to_lookup_table.contains_key(&(p.db.clone(), p.user.clone())) {
result.insert(DatabasePrivilegesDiff::Deleted(p.clone()));
if !to_lookup_table.contains_key(&(p.db.to_owned(), p.user.to_owned())) {
result.insert(DatabasePrivilegesDiff::Deleted(p.to_owned()));
}
}
@@ -593,8 +598,8 @@ mod tests {
assert_eq!(
result.ok(),
Some(DatabasePrivilegeRow {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: true,
insert_priv: true,
update_priv: true,
@@ -613,8 +618,8 @@ mod tests {
assert_eq!(
result.ok(),
Some(DatabasePrivilegeRow {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: false,
insert_priv: false,
update_priv: false,
@@ -633,8 +638,8 @@ mod tests {
assert_eq!(
result.ok(),
Some(DatabasePrivilegeRow {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: true,
insert_priv: true,
update_priv: true,
@@ -668,8 +673,8 @@ mod tests {
#[test]
fn test_diff_privileges() {
let row_to_be_modified = DatabasePrivilegeRow {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: true,
insert_priv: true,
update_priv: true,
@@ -683,20 +688,20 @@ mod tests {
references_priv: false,
};
let mut row_to_be_deleted = row_to_be_modified.clone();
let mut row_to_be_deleted = row_to_be_modified.to_owned();
"user2".clone_into(&mut row_to_be_deleted.user);
let from = vec![row_to_be_modified.clone(), row_to_be_deleted.clone()];
let from = vec![row_to_be_modified.to_owned(), row_to_be_deleted.to_owned()];
let mut modified_row = row_to_be_modified.clone();
let mut modified_row = row_to_be_modified.to_owned();
modified_row.select_priv = false;
modified_row.insert_priv = false;
modified_row.index_priv = true;
let mut new_row = row_to_be_modified.clone();
let mut new_row = row_to_be_modified.to_owned();
"user3".clone_into(&mut new_row.user);
let to = vec![modified_row.clone(), new_row.clone()];
let to = vec![modified_row.to_owned(), new_row.to_owned()];
let diffs = diff_privileges(&from, &to);
@@ -705,8 +710,8 @@ mod tests {
BTreeSet::from_iter(vec![
DatabasePrivilegesDiff::Deleted(row_to_be_deleted),
DatabasePrivilegesDiff::Modified(DatabasePrivilegeRowDiff {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
diff: BTreeSet::from_iter(vec![
DatabasePrivilegeChange::YesToNo("select_priv".to_owned()),
DatabasePrivilegeChange::YesToNo("insert_priv".to_owned()),
@@ -722,8 +727,8 @@ mod tests {
fn ensure_generated_and_parsed_editor_content_is_equal() {
let permissions = vec![
DatabasePrivilegeRow {
db: "db".to_owned(),
user: "user".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: true,
insert_priv: true,
update_priv: true,
@@ -737,8 +742,8 @@ mod tests {
references_priv: true,
},
DatabasePrivilegeRow {
db: "db2".to_owned(),
user: "user2".to_owned(),
db: "db".into(),
user: "user".into(),
select_priv: false,
insert_priv: false,
update_priv: false,

View File

@@ -1,4 +1,9 @@
use std::collections::BTreeSet;
use std::{
collections::BTreeSet,
fmt::{Display, Formatter},
ops::{Deref, DerefMut},
str::FromStr,
};
use serde::{Deserialize, Serialize};
use tokio::net::UnixStream;
@@ -31,21 +36,107 @@ pub fn create_client_to_server_message_stream(socket: UnixStream) -> ClientToSer
tokio_serde::Framed::new(length_delimited, Bincode::default())
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct MySQLUser(String);
impl FromStr for MySQLUser {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(MySQLUser(s.to_string()))
}
}
impl Deref for MySQLUser {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for MySQLUser {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Display for MySQLUser {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for MySQLUser {
fn from(s: &str) -> Self {
MySQLUser(s.to_string())
}
}
impl From<String> for MySQLUser {
fn from(s: String) -> Self {
MySQLUser(s)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct MySQLDatabase(String);
impl FromStr for MySQLDatabase {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(MySQLDatabase(s.to_string()))
}
}
impl Deref for MySQLDatabase {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for MySQLDatabase {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Display for MySQLDatabase {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl From<&str> for MySQLDatabase {
fn from(s: &str) -> Self {
MySQLDatabase(s.to_string())
}
}
impl From<String> for MySQLDatabase {
fn from(s: String) -> Self {
MySQLDatabase(s)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Request {
CreateDatabases(Vec<String>),
DropDatabases(Vec<String>),
ListDatabases(Option<Vec<String>>),
ListPrivileges(Option<Vec<String>>),
CreateDatabases(Vec<MySQLDatabase>),
DropDatabases(Vec<MySQLDatabase>),
ListDatabases(Option<Vec<MySQLDatabase>>),
ListPrivileges(Option<Vec<MySQLDatabase>>),
ModifyPrivileges(BTreeSet<DatabasePrivilegesDiff>),
CreateUsers(Vec<String>),
DropUsers(Vec<String>),
PasswdUser(String, String),
ListUsers(Option<Vec<String>>),
LockUsers(Vec<String>),
UnlockUsers(Vec<String>),
CreateUsers(Vec<MySQLUser>),
DropUsers(Vec<MySQLUser>),
PasswdUser(MySQLUser, String),
ListUsers(Option<Vec<MySQLUser>>),
LockUsers(Vec<MySQLUser>),
UnlockUsers(Vec<MySQLUser>),
// Commit,
Exit,

View File

@@ -13,6 +13,8 @@ use crate::{
},
};
use super::{MySQLDatabase, MySQLUser};
/// This enum is used to differentiate between database and user operations.
/// Their output are very similar, but there are slight differences in the words used.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -22,17 +24,17 @@ pub enum DbOrUser {
}
impl DbOrUser {
pub fn lowercased(&self) -> String {
pub fn lowercased(&self) -> &'static str {
match self {
DbOrUser::Database => "database".to_string(),
DbOrUser::User => "user".to_string(),
DbOrUser::Database => "database",
DbOrUser::User => "user",
}
}
pub fn capitalized(&self) -> String {
pub fn capitalized(&self) -> &'static str {
match self {
DbOrUser::Database => "Database".to_string(),
DbOrUser::User => "User".to_string(),
DbOrUser::Database => "Database",
DbOrUser::User => "User",
}
}
}
@@ -73,6 +75,11 @@ impl OwnerValidationError {
pub fn to_error_message(self, name: &str, db_or_user: DbOrUser) -> String {
let user = UnixUser::from_enviroment();
let UnixUser { username, groups } = user.unwrap_or(UnixUser {
username: "???".to_string(),
groups: vec![],
});
match self {
OwnerValidationError::NoMatch => format!(
indoc! {r#"
@@ -88,11 +95,8 @@ impl OwnerValidationError {
name,
db_or_user.lowercased(),
db_or_user.lowercased(),
user.as_ref()
.map(|u| u.username.clone())
.unwrap_or("???".to_string()),
user.map(|u| u.groups)
.unwrap_or_default()
username,
groups
.iter()
.map(|g| format!(" - {}", g))
.sorted()
@@ -118,7 +122,7 @@ pub enum OwnerValidationError {
StringEmpty,
}
pub type CreateDatabasesOutput = BTreeMap<String, Result<(), CreateDatabaseError>>;
pub type CreateDatabasesOutput = BTreeMap<MySQLDatabase, Result<(), CreateDatabaseError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CreateDatabaseError {
SanitizationError(NameValidationError),
@@ -146,9 +150,9 @@ pub fn print_create_databases_output_status_json(output: &CreateDatabasesOutput)
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -164,7 +168,7 @@ pub fn print_create_databases_output_status_json(output: &CreateDatabasesOutput)
}
impl CreateDatabaseError {
pub fn to_error_message(&self, database_name: &str) -> String {
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
match self {
CreateDatabaseError::SanitizationError(err) => {
err.to_error_message(database_name, DbOrUser::Database)
@@ -182,7 +186,7 @@ impl CreateDatabaseError {
}
}
pub type DropDatabasesOutput = BTreeMap<String, Result<(), DropDatabaseError>>;
pub type DropDatabasesOutput = BTreeMap<MySQLDatabase, Result<(), DropDatabaseError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DropDatabaseError {
SanitizationError(NameValidationError),
@@ -195,7 +199,10 @@ pub fn print_drop_databases_output_status(output: &DropDatabasesOutput) {
for (database_name, result) in output {
match result {
Ok(()) => {
println!("Database '{}' dropped successfully.", database_name);
println!(
"Database '{}' dropped successfully.",
database_name.as_str()
);
}
Err(err) => {
println!("{}", err.to_error_message(database_name));
@@ -210,9 +217,9 @@ pub fn print_drop_databases_output_status_json(output: &DropDatabasesOutput) {
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -228,7 +235,7 @@ pub fn print_drop_databases_output_status_json(output: &DropDatabasesOutput) {
}
impl DropDatabaseError {
pub fn to_error_message(&self, database_name: &str) -> String {
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
match self {
DropDatabaseError::SanitizationError(err) => {
err.to_error_message(database_name, DbOrUser::Database)
@@ -246,7 +253,7 @@ impl DropDatabaseError {
}
}
pub type ListDatabasesOutput = BTreeMap<String, Result<DatabaseRow, ListDatabasesError>>;
pub type ListDatabasesOutput = BTreeMap<MySQLDatabase, Result<DatabaseRow, ListDatabasesError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ListDatabasesError {
SanitizationError(NameValidationError),
@@ -256,7 +263,7 @@ pub enum ListDatabasesError {
}
impl ListDatabasesError {
pub fn to_error_message(&self, database_name: &str) -> String {
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
match self {
ListDatabasesError::SanitizationError(err) => {
err.to_error_message(database_name, DbOrUser::Database)
@@ -293,7 +300,7 @@ impl ListAllDatabasesError {
// no need to index by database name.
pub type GetDatabasesPrivilegeData =
BTreeMap<String, Result<Vec<DatabasePrivilegeRow>, GetDatabasesPrivilegeDataError>>;
BTreeMap<MySQLDatabase, Result<Vec<DatabasePrivilegeRow>, GetDatabasesPrivilegeDataError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum GetDatabasesPrivilegeDataError {
SanitizationError(NameValidationError),
@@ -303,7 +310,7 @@ pub enum GetDatabasesPrivilegeDataError {
}
impl GetDatabasesPrivilegeDataError {
pub fn to_error_message(&self, database_name: &str) -> String {
pub fn to_error_message(&self, database_name: &MySQLDatabase) -> String {
match self {
GetDatabasesPrivilegeDataError::SanitizationError(err) => {
err.to_error_message(database_name, DbOrUser::Database)
@@ -337,7 +344,7 @@ impl GetAllDatabasesPrivilegeDataError {
}
pub type ModifyDatabasePrivilegesOutput =
BTreeMap<(String, String), Result<(), ModifyDatabasePrivilegesError>>;
BTreeMap<(MySQLDatabase, MySQLUser), Result<(), ModifyDatabasePrivilegesError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ModifyDatabasePrivilegesError {
DatabaseSanitizationError(NameValidationError),
@@ -352,8 +359,8 @@ pub enum ModifyDatabasePrivilegesError {
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DiffDoesNotApplyError {
RowAlreadyExists(String, String),
RowDoesNotExist(String, String),
RowAlreadyExists(MySQLDatabase, MySQLUser),
RowDoesNotExist(MySQLDatabase, MySQLUser),
RowPrivilegeChangeDoesNotApply(DatabasePrivilegeRowDiff, DatabasePrivilegeRow),
}
@@ -376,7 +383,7 @@ pub fn print_modify_database_privileges_output_status(output: &ModifyDatabasePri
}
impl ModifyDatabasePrivilegesError {
pub fn to_error_message(&self, database_name: &str, username: &str) -> String {
pub fn to_error_message(&self, database_name: &MySQLDatabase, username: &MySQLUser) -> String {
match self {
ModifyDatabasePrivilegesError::DatabaseSanitizationError(err) => {
err.to_error_message(database_name, DbOrUser::Database)
@@ -431,7 +438,7 @@ impl DiffDoesNotApplyError {
}
}
pub type CreateUsersOutput = BTreeMap<String, Result<(), CreateUserError>>;
pub type CreateUsersOutput = BTreeMap<MySQLUser, Result<(), CreateUserError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CreateUserError {
SanitizationError(NameValidationError),
@@ -459,9 +466,9 @@ pub fn print_create_users_output_status_json(output: &CreateUsersOutput) {
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -477,7 +484,7 @@ pub fn print_create_users_output_status_json(output: &CreateUsersOutput) {
}
impl CreateUserError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
CreateUserError::SanitizationError(err) => {
err.to_error_message(username, DbOrUser::User)
@@ -493,7 +500,7 @@ impl CreateUserError {
}
}
pub type DropUsersOutput = BTreeMap<String, Result<(), DropUserError>>;
pub type DropUsersOutput = BTreeMap<MySQLUser, Result<(), DropUserError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DropUserError {
SanitizationError(NameValidationError),
@@ -521,9 +528,9 @@ pub fn print_drop_users_output_status_json(output: &DropUsersOutput) {
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -539,7 +546,7 @@ pub fn print_drop_users_output_status_json(output: &DropUsersOutput) {
}
impl DropUserError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
DropUserError::SanitizationError(err) => err.to_error_message(username, DbOrUser::User),
DropUserError::OwnershipError(err) => err.to_error_message(username, DbOrUser::User),
@@ -562,7 +569,7 @@ pub enum SetPasswordError {
MySqlError(String),
}
pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &str) {
pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &MySQLUser) {
match output {
Ok(()) => {
println!("Password for user '{}' set successfully.", username);
@@ -575,7 +582,7 @@ pub fn print_set_password_output_status(output: &SetPasswordOutput, username: &s
}
impl SetPasswordError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
SetPasswordError::SanitizationError(err) => {
err.to_error_message(username, DbOrUser::User)
@@ -591,7 +598,7 @@ impl SetPasswordError {
}
}
pub type LockUsersOutput = BTreeMap<String, Result<(), LockUserError>>;
pub type LockUsersOutput = BTreeMap<MySQLUser, Result<(), LockUserError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum LockUserError {
SanitizationError(NameValidationError),
@@ -620,9 +627,9 @@ pub fn print_lock_users_output_status_json(output: &LockUsersOutput) {
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -638,7 +645,7 @@ pub fn print_lock_users_output_status_json(output: &LockUsersOutput) {
}
impl LockUserError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
LockUserError::SanitizationError(err) => err.to_error_message(username, DbOrUser::User),
LockUserError::OwnershipError(err) => err.to_error_message(username, DbOrUser::User),
@@ -655,7 +662,7 @@ impl LockUserError {
}
}
pub type UnlockUsersOutput = BTreeMap<String, Result<(), UnlockUserError>>;
pub type UnlockUsersOutput = BTreeMap<MySQLUser, Result<(), UnlockUserError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum UnlockUserError {
SanitizationError(NameValidationError),
@@ -684,9 +691,9 @@ pub fn print_unlock_users_output_status_json(output: &UnlockUsersOutput) {
let value = output
.iter()
.map(|(name, result)| match result {
Ok(()) => (name.to_owned(), json!({ "status": "success" })),
Ok(()) => (name.to_string(), json!({ "status": "success" })),
Err(err) => (
name.clone(),
name.to_string(),
json!({
"status": "error",
"error": err.to_error_message(name),
@@ -702,7 +709,7 @@ pub fn print_unlock_users_output_status_json(output: &UnlockUsersOutput) {
}
impl UnlockUserError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
UnlockUserError::SanitizationError(err) => {
err.to_error_message(username, DbOrUser::User)
@@ -721,7 +728,7 @@ impl UnlockUserError {
}
}
pub type ListUsersOutput = BTreeMap<String, Result<DatabaseUser, ListUsersError>>;
pub type ListUsersOutput = BTreeMap<MySQLUser, Result<DatabaseUser, ListUsersError>>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ListUsersError {
SanitizationError(NameValidationError),
@@ -731,7 +738,7 @@ pub enum ListUsersError {
}
impl ListUsersError {
pub fn to_error_message(&self, username: &str) -> String {
pub fn to_error_message(&self, username: &MySQLUser) -> String {
match self {
ListUsersError::SanitizationError(err) => {
err.to_error_message(username, DbOrUser::User)