1
use std::collections::{BTreeMap, BTreeSet};
2

            
3
use serde::{Deserialize, Serialize};
4
use thiserror::Error;
5

            
6
use crate::core::{
7
    database_privileges::{DatabasePrivilegeRow, DatabasePrivilegeRowDiff, DatabasePrivilegesDiff},
8
    protocol::request_validation::ValidationError,
9
    types::{DbOrUser, MySQLDatabase, MySQLUser},
10
};
11

            
12
pub type ModifyPrivilegesRequest = BTreeSet<DatabasePrivilegesDiff>;
13

            
14
pub type ModifyPrivilegesResponse =
15
    BTreeMap<(MySQLDatabase, MySQLUser), Result<(), ModifyDatabasePrivilegesError>>;
16

            
17
#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
18
pub enum ModifyDatabasePrivilegesError {
19
    #[error("Database validation error: {0}")]
20
    DatabaseValidationError(ValidationError),
21

            
22
    #[error("User validation error: {0}")]
23
    UserValidationError(ValidationError),
24

            
25
    #[error("Database does not exist")]
26
    DatabaseDoesNotExist,
27

            
28
    #[error("User does not exist")]
29
    UserDoesNotExist,
30

            
31
    #[error("Diff does not apply: {0}")]
32
    DiffDoesNotApply(DiffDoesNotApplyError),
33

            
34
    #[error("MySQL error: {0}")]
35
    MySqlError(String),
36
}
37

            
38
#[allow(clippy::enum_variant_names)]
39
#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
40
pub enum DiffDoesNotApplyError {
41
    #[error("Privileges row already exists for database '{0}' and user '{1}'")]
42
    RowAlreadyExists(MySQLDatabase, MySQLUser),
43

            
44
    #[error("Privileges row does not exist for database '{0}' and user '{1}'")]
45
    RowDoesNotExist(MySQLDatabase, MySQLUser),
46

            
47
    #[error("Privilege change '{0:?}' does not apply to row '{1:?}'")]
48
    RowPrivilegeChangeDoesNotApply(DatabasePrivilegeRowDiff, DatabasePrivilegeRow),
49
}
50

            
51
pub fn print_modify_database_privileges_output_status(output: &ModifyPrivilegesResponse) {
52
    for ((database_name, username), result) in output {
53
        match result {
54
            Ok(()) => {
55
                println!(
56
                    "Privileges for user '{username}' on database '{database_name}' modified successfully."
57
                );
58
            }
59
            Err(err) => {
60
                eprintln!("{}", err.to_error_message(database_name, username));
61
                eprintln!("Skipping...");
62
            }
63
        }
64
        println!();
65
    }
66
}
67

            
68
impl ModifyDatabasePrivilegesError {
69
    #[must_use]
70
    pub fn to_error_message(&self, database_name: &MySQLDatabase, username: &MySQLUser) -> String {
71
        match self {
72
            ModifyDatabasePrivilegesError::DatabaseValidationError(err) => {
73
                err.to_error_message(&DbOrUser::Database(database_name.clone()))
74
            }
75
            ModifyDatabasePrivilegesError::UserValidationError(err) => {
76
                err.to_error_message(&DbOrUser::User(username.clone()))
77
            }
78
            ModifyDatabasePrivilegesError::DatabaseDoesNotExist => {
79
                format!("Database '{database_name}' does not exist.")
80
            }
81
            ModifyDatabasePrivilegesError::UserDoesNotExist => {
82
                format!("User '{username}' does not exist.")
83
            }
84
            ModifyDatabasePrivilegesError::DiffDoesNotApply(diff) => {
85
                format!(
86
                    "Could not apply privilege change:\n{}",
87
                    diff.to_error_message()
88
                )
89
            }
90
            ModifyDatabasePrivilegesError::MySqlError(err) => {
91
                format!("MySQL error: {err}")
92
            }
93
        }
94
    }
95

            
96
    #[allow(dead_code)]
97
    #[must_use]
98
    pub fn error_type(&self) -> String {
99
        match self {
100
            ModifyDatabasePrivilegesError::DatabaseValidationError(err) => {
101
                err.error_type() + "/database"
102
            }
103
            ModifyDatabasePrivilegesError::UserValidationError(err) => err.error_type() + "/user",
104
            ModifyDatabasePrivilegesError::DatabaseDoesNotExist => {
105
                "database-does-not-exist".to_string()
106
            }
107
            ModifyDatabasePrivilegesError::UserDoesNotExist => "user-does-not-exist".to_string(),
108
            ModifyDatabasePrivilegesError::DiffDoesNotApply(err) => {
109
                format!("diff-does-not-apply/{}", err.error_type())
110
            }
111
            ModifyDatabasePrivilegesError::MySqlError(_) => "mysql-error".to_string(),
112
        }
113
    }
114
}
115

            
116
impl DiffDoesNotApplyError {
117
    #[must_use]
118
    pub fn to_error_message(&self) -> String {
119
        match self {
120
            DiffDoesNotApplyError::RowAlreadyExists(database_name, username) => {
121
                format!(
122
                    "Privileges for user '{username}' on database '{database_name}' already exist."
123
                )
124
            }
125
            DiffDoesNotApplyError::RowDoesNotExist(database_name, username) => {
126
                format!(
127
                    "Privileges for user '{username}' on database '{database_name}' do not exist."
128
                )
129
            }
130
            DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(diff, row) => {
131
                format!("Could not apply privilege change {diff:?} to row {row:?}")
132
            }
133
        }
134
    }
135

            
136
    #[must_use]
137
    pub fn error_type(&self) -> String {
138
        match self {
139
            DiffDoesNotApplyError::RowAlreadyExists(_, _) => "row-already-exists".to_string(),
140
            DiffDoesNotApplyError::RowDoesNotExist(_, _) => "row-does-not-exist".to_string(),
141
            DiffDoesNotApplyError::RowPrivilegeChangeDoesNotApply(_, _) => {
142
                "row-privilege-change-does-not-apply".to_string()
143
            }
144
        }
145
    }
146
}