1
use bonsaidb_core::connection::{AsyncStorageConnection, StorageConnection};
2
use clap::Subcommand;
3

            
4
/// An administrative command-line command.
5
#[derive(Subcommand, Debug)]
6
pub enum Command {
7
    /// A command operating on [`User`s](bonsaidb_core::admin::User).
8
    #[clap(subcommand)]
9
    User(UserCommand),
10
}
11

            
12
/// A command operating on [`User`s](bonsaidb_core::admin::User).
13
252
#[derive(Subcommand, Debug)]
14
pub enum UserCommand {
15
    /// Creates a new user.
16
    Create {
17
        /// The username of the user to create.
18
        username: String,
19
        /// If this flag is provided, the user's initial password will be
20
        /// prompted for over stdin before creating the user.
21
        #[cfg(feature = "password-hashing")]
22
        #[clap(long)]
23
        password: bool,
24
    },
25
    /// Sets an existing user's password. The password will be prompted for over
26
    /// stdin.
27
    #[cfg(feature = "password-hashing")]
28
    SetPassword {
29
        /// The username of the user to change the password of.
30
        username: String,
31
    },
32
    /// Adds a role to a user.
33
    AddRole {
34
        /// The username to add the role to.
35
        username: String,
36
        /// The name of the role to add.
37
        role: String,
38
    },
39
    /// Removes a role from user.
40
    RemoveRole {
41
        /// The username to remove the role from.
42
        username: String,
43
        /// The name of the role to remove.
44
        role: String,
45
    },
46
    /// Adds a role to a user.
47
    AddGroup {
48
        /// The username to add the role to.
49
        username: String,
50
        /// The name of the role to add.
51
        group: String,
52
    },
53
    /// Removes a permission group from user.
54
    RemoveGroup {
55
        /// The username to remove the permission group from.
56
        username: String,
57
        /// The name of the permission group to remove.
58
        group: String,
59
    },
60
}
61

            
62
impl Command {
63
    /// Executes the command on `storage`.
64
    pub fn execute<SC: StorageConnection>(self, storage: &SC) -> Result<(), crate::Error> {
65
        match self {
66
            Command::User(user) => match user {
67
                UserCommand::Create { username, password } => {
68
                    #[cfg(feature = "password-hashing")]
69
                    let password = if password {
70
                        Some(super::read_password_from_stdin(true)?)
71
                    } else {
72
                        None
73
                    };
74
                    let user_id = storage.create_user(&username)?;
75

            
76
                    #[cfg(feature = "password-hashing")]
77
                    if let Some(password) = password {
78
                        storage.set_user_password(user_id, password)?;
79
                    }
80

            
81
                    println!("User #{user_id} {username} created");
82
                    Ok(())
83
                }
84
                #[cfg(feature = "password-hashing")]
85
                UserCommand::SetPassword { username } => {
86
                    let password = super::read_password_from_stdin(true)?;
87
                    storage.set_user_password(&username, password)?;
88
                    println!("User {username}'s password has been updated.");
89
                    Ok(())
90
                }
91
                UserCommand::AddRole { username, role } => {
92
                    storage.add_role_to_user(&username, &role)?;
93
                    println!("Role {role} added to {username}");
94
                    Ok(())
95
                }
96
                UserCommand::RemoveRole { username, role } => {
97
                    storage.remove_role_from_user(&username, &role)?;
98
                    println!("Role {role} removed from {username}");
99
                    Ok(())
100
                }
101
                UserCommand::AddGroup { username, group } => {
102
                    storage.add_permission_group_to_user(&username, &group)?;
103
                    println!("Group {group} added to {username}");
104
                    Ok(())
105
                }
106
                UserCommand::RemoveGroup { username, group } => {
107
                    storage.remove_permission_group_from_user(&username, &group)?;
108
                    println!("Group {group} removed from {username}");
109
                    Ok(())
110
                }
111
            },
112
        }
113
    }
114

            
115
    /// Executes the command on `storage`.
116
    pub async fn execute_async<SC: AsyncStorageConnection>(
117
        self,
118
        storage: &SC,
119
    ) -> Result<(), crate::Error> {
120
        match self {
121
            Command::User(user) => match user {
122
                UserCommand::Create { username, password } => {
123
                    #[cfg(feature = "password-hashing")]
124
                    let password = if password {
125
                        Some(super::read_password_from_stdin(true)?)
126
                    } else {
127
                        None
128
                    };
129
                    let user_id = storage.create_user(&username).await?;
130

            
131
                    #[cfg(feature = "password-hashing")]
132
                    if let Some(password) = password {
133
                        storage.set_user_password(user_id, password).await?;
134
                    }
135

            
136
                    println!("User #{user_id} {username} created");
137
                    Ok(())
138
                }
139
                #[cfg(feature = "password-hashing")]
140
                UserCommand::SetPassword { username } => {
141
                    let password = super::read_password_from_stdin(true)?;
142
                    storage.set_user_password(&username, password).await?;
143
                    println!("User {username}'s password has been updated.");
144
                    Ok(())
145
                }
146
                UserCommand::AddRole { username, role } => {
147
                    storage.add_role_to_user(&username, &role).await?;
148
                    println!("Role {role} added to {username}");
149
                    Ok(())
150
                }
151
                UserCommand::RemoveRole { username, role } => {
152
                    storage.remove_role_from_user(&username, &role).await?;
153
                    println!("Role {role} removed from {username}");
154
                    Ok(())
155
                }
156
                UserCommand::AddGroup { username, group } => {
157
                    storage
158
                        .add_permission_group_to_user(&username, &group)
159
                        .await?;
160
                    println!("Group {group} added to {username}");
161
                    Ok(())
162
                }
163
                UserCommand::RemoveGroup { username, group } => {
164
                    storage
165
                        .remove_permission_group_from_user(&username, &group)
166
                        .await?;
167
                    println!("Group {group} removed from {username}");
168
                    Ok(())
169
                }
170
            },
171
        }
172
    }
173
}