grant/
inspect.rs

1use crate::config::Config;
2use crate::connection::{DbConnection, UserDatabaseRole, UserSchemaRole, UserTableRole};
3use anyhow::{anyhow, Result};
4use ascii_table::AsciiTable;
5use indoc::indoc;
6use log::info;
7
8pub fn inspect(config: &Config) -> Result<()> {
9    let mut conn = DbConnection::new(config)?;
10
11    let users_in_db = conn.get_users()?;
12    let current_db_name = conn
13        .get_current_database()
14        .map(|s| s.to_string())
15        .ok_or_else(|| anyhow!("Could not determine current database"))?;
16
17    let user_database_privileges = conn
18        .get_user_database_privileges()?
19        .into_iter()
20        .filter(|p| p.database_name == current_db_name)
21        .collect::<Vec<_>>();
22    let user_schema_privileges = conn.get_user_schema_privileges()?;
23    let user_table_privileges = conn.get_user_table_privileges()?;
24
25    let mut users = users_in_db
26        .iter()
27        .map(|u| {
28            vec![
29                u.name.clone(),
30                u.user_super.to_string(),
31                get_user_database_privileges(&user_database_privileges, &u.name).unwrap(),
32                get_user_schema_privileges(&user_schema_privileges, &u.name).unwrap(),
33                get_user_table_privileges(&user_table_privileges, &u.name).unwrap(),
34            ]
35        })
36        .collect::<Vec<_>>();
37
38    users.insert(
39        0,
40        vec![
41            "User".to_string(),
42            "Super".to_string(),
43            "Current Database".to_string(),
44            "Schemas".to_string(),
45            "Tables".to_string(),
46        ],
47    );
48    users.insert(
49        1,
50        vec![
51            "---".to_string(),
52            "---".to_string(),
53            "---".to_string(),
54            "---".to_string(),
55        ],
56    );
57
58    // Get the terminal with
59    let term_width = term_size::dimensions().map(|(w, _)| w).unwrap_or(120) - 5;
60
61    // Print the table in max size
62    let mut table = AsciiTable::default();
63    table.set_max_width(term_width);
64
65    info!(
66        "Current users in {}:\n{}",
67        config.connection.url,
68        table.format(users)
69    );
70
71    info!(indoc! { r#"
72        == Legend ==
73
74        Database:
75            A = ALL Privileges
76            C = CREATE
77            T = TEMP
78
79        Schema:
80            A = ALL Privileges
81            C = CREATE
82            U = USAGE
83
84        Table:
85            A = ALL Privileges
86            S = SELECT
87            U = UPDATE
88            I = INSERT
89            D = DELETE
90            R = REFERENCES
91    "#});
92
93    Ok(())
94}
95
96/// Get current user database privileges
97fn get_user_database_privileges(privileges: &[UserDatabaseRole], user: &str) -> Result<String> {
98    let privileges = privileges
99        .iter()
100        .filter(|p| p.name == *user) // is current user
101        .filter(|p| p.has_create || p.has_temp) // has at least create or temp
102        .map(|p| p.perm_to_string(true))
103        .collect::<Vec<_>>()
104        .join(", ");
105
106    Ok(privileges)
107}
108
109/// Get current user schema privileges
110fn get_user_schema_privileges(privileges: &[UserSchemaRole], user: &str) -> Result<String> {
111    let privileges = privileges
112        .iter()
113        .filter(|p| p.name == *user)
114        .filter(|p| p.has_create || p.has_usage)
115        .map(|p| p.perm_to_string(true))
116        .collect::<Vec<_>>()
117        .join(", ");
118
119    Ok(privileges)
120}
121
122/// Get current user schema.table privileges
123fn get_user_table_privileges(privileges: &[UserTableRole], user: &str) -> Result<String> {
124    let privileges = privileges
125        .iter()
126        .filter(|p| p.name == *user) // is current user
127        .filter(|p| {
128            p.has_select || p.has_insert || p.has_update || p.has_delete || p.has_references
129        }) // has at least create or select
130        .map(|p| p.perm_to_string(true))
131        .collect::<Vec<_>>()
132        .join(", ");
133
134    Ok(privileges)
135}