1
use serde::{Deserialize, Serialize};
2
use thiserror::Error;
3

            
4
use crate::core::{
5
    protocol::request_validation::ValidationError,
6
    types::{DbOrUser, MySQLUser},
7
};
8

            
9
/// The desired new password for a user, either provided explicitly,
10
/// generated by the server, or cleared.
11
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12
pub enum PasswordSource {
13
    Explicit(String),
14
    Generate,
15
    Clear,
16
}
17

            
18
pub type SetUserPasswordRequest = (MySQLUser, PasswordSource);
19

            
20
/// The generated password is returned when the request used
21
/// [`PasswordSource::Generate`], and is `None` otherwise.
22
pub type SetUserPasswordResponse = Result<Option<String>, SetPasswordError>;
23

            
24
#[derive(Error, Debug, Clone, PartialEq, Serialize, Deserialize)]
25
pub enum SetPasswordError {
26
    #[error("Validation error: {0}")]
27
    ValidationError(#[from] ValidationError),
28

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

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

            
36
pub fn print_set_password_output_status(output: &SetUserPasswordResponse, username: &MySQLUser) {
37
    match output {
38
        Ok(None) => {
39
            println!("Password for user '{username}' set successfully.");
40
        }
41
        Ok(Some(generated_password)) => {
42
            println!("Password for user '{username}' generated successfully: {generated_password}");
43
        }
44
        Err(err) => {
45
            eprintln!("{}", err.to_error_message(username));
46
            eprintln!("Skipping...");
47
        }
48
    }
49
}
50

            
51
impl SetPasswordError {
52
    #[must_use]
53
    pub fn to_error_message(&self, username: &MySQLUser) -> String {
54
        match self {
55
            SetPasswordError::ValidationError(err) => {
56
                err.to_error_message(&DbOrUser::User(username.clone()))
57
            }
58
            SetPasswordError::UserDoesNotExist => {
59
                format!("User '{username}' does not exist.")
60
            }
61
            SetPasswordError::MySqlError(err) => {
62
                format!("MySQL error: {err}")
63
            }
64
        }
65
    }
66

            
67
    #[allow(dead_code)]
68
    #[must_use]
69
    pub fn error_type(&self) -> String {
70
        match self {
71
            SetPasswordError::ValidationError(err) => err.error_type(),
72
            SetPasswordError::UserDoesNotExist => "user-does-not-exist".to_string(),
73
            SetPasswordError::MySqlError(_) => "mysql-error".to_string(),
74
        }
75
    }
76
}
77

            
78
#[cfg(test)]
79
mod tests {
80
    use super::*;
81

            
82
    #[test]
83
1
    fn test_serialize_deserialize_explicit_request() {
84
1
        let request: SetUserPasswordRequest = (
85
1
            "test_user".into(),
86
1
            PasswordSource::Explicit("new_password".into()),
87
1
        );
88

            
89
1
        let json = serde_json::to_string_pretty(&request).unwrap();
90
1
        println!("Serialized request:\n{}", json);
91

            
92
1
        let deserialized: SetUserPasswordRequest = serde_json::from_str(&json).unwrap();
93
1
        assert_eq!(request, deserialized);
94
1
    }
95

            
96
    #[test]
97
1
    fn test_serialize_deserialize_generate_request() {
98
1
        let request: SetUserPasswordRequest = ("test_user".into(), PasswordSource::Generate);
99

            
100
1
        let json = serde_json::to_string_pretty(&request).unwrap();
101
1
        println!("Serialized request:\n{}", json);
102

            
103
1
        let deserialized: SetUserPasswordRequest = serde_json::from_str(&json).unwrap();
104
1
        assert_eq!(request, deserialized);
105
1
    }
106

            
107
    #[test]
108
1
    fn test_serialize_deserialize_clear_request() {
109
1
        let request: SetUserPasswordRequest = ("test_user".into(), PasswordSource::Clear);
110

            
111
1
        let json = serde_json::to_string_pretty(&request).unwrap();
112
1
        println!("Serialized request:\n{}", json);
113

            
114
1
        let deserialized: SetUserPasswordRequest = serde_json::from_str(&json).unwrap();
115
1
        assert_eq!(request, deserialized);
116
1
    }
117

            
118
    #[test]
119
1
    fn test_serialize_deserialize_response() {
120
1
        let response_ok: SetUserPasswordResponse = Ok(None);
121
1
        let response_generated: SetUserPasswordResponse = Ok(Some("generated_password".into()));
122
1
        let response_err: SetUserPasswordResponse = Err(SetPasswordError::UserDoesNotExist);
123

            
124
1
        let json_ok = serde_json::to_string_pretty(&response_ok).unwrap();
125
1
        let json_generated = serde_json::to_string_pretty(&response_generated).unwrap();
126
1
        let json_err = serde_json::to_string_pretty(&response_err).unwrap();
127
1
        println!("Serialized OK response:\n{}", json_ok);
128
1
        println!("Serialized generated response:\n{}", json_generated);
129
1
        println!("Serialized Error response:\n{}", json_err);
130

            
131
1
        let deserialized_ok: SetUserPasswordResponse = serde_json::from_str(&json_ok).unwrap();
132
1
        let deserialized_generated: SetUserPasswordResponse =
133
1
            serde_json::from_str(&json_generated).unwrap();
134
1
        let deserialized_err: SetUserPasswordResponse = serde_json::from_str(&json_err).unwrap();
135
1
        assert_eq!(response_ok, deserialized_ok);
136
1
        assert_eq!(response_generated, deserialized_generated);
137
1
        assert_eq!(response_err, deserialized_err);
138
1
    }
139
}